// Package wechat
// Created by GoLand
// @User: lenora
// @Date: 2024/1/3
// @Time: 12:39

package wechat

import (
	"camp/microbook/internal/domain"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

const CallbackUrl = "https://skjadhsa.com/oauth2/wechat/callback"

type Service interface {
	AuthURL(state string) string
	VerifyCode(ctx context.Context, code string) (domain.WechatInfo, error)
}

type service struct {
	appId     string
	appSecret string
	client    *http.Client
}

func NewService(appId, appSecret string) Service {
	return &service{
		appId:     appId,
		appSecret: appSecret,
		client:    http.DefaultClient,
	}
}

func (s *service) AuthURL(state string) string {
	const format = `https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login&state=%s#wechat_redirect`
	return fmt.Sprintf(format, s.appId, url.PathEscape(CallbackUrl), state)
}

func (s *service) VerifyCode(ctx context.Context, code string) (domain.WechatInfo, error) {
	format := `https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code`
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf(format, s.appId, s.appSecret, code), nil)
	if err != nil {
		return domain.WechatInfo{}, err
	}
	httpResp, err := s.client.Do(req)
	if err != nil {
		return domain.WechatInfo{}, err
	}
	var resp ResponseResult
	err = json.NewDecoder(httpResp.Body).Decode(&resp)
	if err != nil {
		return domain.WechatInfo{}, err
	}
	if resp.ErrCode != 0 {
		return domain.WechatInfo{}, fmt.Errorf("%s", resp.ErrMsg)
	}
	return domain.WechatInfo{
		AccessToken:  resp.AccessToken,
		ExpiresIn:    resp.ExpiresIn,
		RefreshToken: resp.RefreshToken,
		Openid:       resp.Openid,
		UnionID:      resp.UnionID,
	}, nil
}

type ResponseResult struct {
	AccessToken  string `json:"access_token"`  //接口调用凭证
	ExpiresIn    int32  `json:"expires_in"`    //access_token接口调用凭证超时时间，单位（秒）
	RefreshToken string `json:"refresh_token"` //用户刷新access_token
	Openid       string `json:"openid"`        //	授权用户唯一标识
	Scope        string `json:"scope"`         //用户授权的作用域，使用逗号（,）分隔
	UnionID      string `json:"unionid"`       //当且仅当该网站应用已获得该用户的userinfo授权时，才会出现该字段
	//错误返回
	ErrCode int32  `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
}
